package com.nnnu.wsnackshop.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class RedisConfig {

        /**
         * Lettuce 连接工厂，读取 application.yml 中 spring.redis.* 配置
         */
        @Bean
        public LettuceConnectionFactory redisConnectionFactory() {
                return new LettuceConnectionFactory();
        }

        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
                RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
                redisTemplate.setConnectionFactory(connectionFactory);

                // 为 Redis 序列化创建独立的 ObjectMapper 实例
                ObjectMapper redisObjectMapper = new ObjectMapper();
                redisObjectMapper.registerModule(new JavaTimeModule());
                redisObjectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
                // 仅对此 ObjectMapper 启用默认类型信息，以处理泛型 Result<T>
                redisObjectMapper.activateDefaultTyping(
                                LaissezFaireSubTypeValidator.instance,
                                ObjectMapper.DefaultTyping.NON_FINAL);

                GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(
                                redisObjectMapper);

                redisTemplate.setKeySerializer(new StringRedisSerializer());
                redisTemplate.setValueSerializer(serializer);
                redisTemplate.setHashKeySerializer(new StringRedisSerializer());
                redisTemplate.setHashValueSerializer(serializer);

                redisTemplate.afterPropertiesSet();
                return redisTemplate;
        }

        @Bean
        public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
                // 为 Redis 缓存管理器序列化创建独立的 ObjectMapper 实例
                ObjectMapper redisObjectMapper = new ObjectMapper();
                redisObjectMapper.registerModule(new JavaTimeModule());
                redisObjectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
                // 仅对此 ObjectMapper 启用默认类型信息，以处理泛型 Result<T>
                redisObjectMapper.activateDefaultTyping(
                                LaissezFaireSubTypeValidator.instance,
                                ObjectMapper.DefaultTyping.NON_FINAL);

                GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(
                                redisObjectMapper);

                // 默认缓存配置
                RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
                                .entryTtl(Duration.ofMinutes(60))
                                .disableCachingNullValues()
                                .serializeKeysWith(
                                                RedisSerializationContext.SerializationPair
                                                                .fromSerializer(new StringRedisSerializer()))
                                .serializeValuesWith(
                                                RedisSerializationContext.SerializationPair.fromSerializer(serializer));

                // 为不同的缓存设置不同的过期时间
                return RedisCacheManager.builder(connectionFactory)
                                .cacheDefaults(defaultConfig)
                                .withCacheConfiguration("userProductPage",
                                                defaultConfig.entryTtl(Duration.ofMinutes(5))) // 商品分页查询缓存5分钟
                                .withCacheConfiguration("userProductPopular",
                                                defaultConfig.entryTtl(Duration.ofMinutes(30))) // 热门商品缓存30分钟
                                .withCacheConfiguration("userProductByStoreCategory",
                                                defaultConfig.entryTtl(Duration.ofMinutes(15))) // 分类商品缓存15分钟
                                .withCacheConfiguration("userProductByCategory",
                                                defaultConfig.entryTtl(Duration.ofMinutes(5))) // 分类商品缓存5分钟，支持排序
                                .transactionAware()
                                .build();
        }
}
